package com.leyou.search.service.impl;

import com.leyou.api.controller.FeignController;
import com.leyou.common.dto.PageDTO;
import com.leyou.common.exception.LyException;
import com.leyou.pojo.dto.QueryPageDto;
import com.leyou.pojo.dto.SkuDto;
import com.leyou.pojo.dto.SpecParamDto;
import com.leyou.pojo.dto.SpuDto;
import com.leyou.search.Reposity.GoodsRepository;
import com.leyou.search.controller.WebController;
import com.leyou.search.entity.Goods;
import com.leyou.search.entity.Search;
import com.leyou.search.service.SearchService;
import com.leyou.starter.elastic.dto.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Mono;

import java.util.*;
import java.util.logging.Logger;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SearchServiceImpl implements SearchService {
    @Autowired
    private FeignController feignController;
    @Autowired
    private GoodsRepository repository;
    @Override
    public void getData() {
        //创建索引库
        this.createIndex();
        //加载数据
        this.loadData();

    }

    /**
     * 自动补全查询
     * @param key
     * @return
     */
    @Override
    public Mono<List<String>> autoCompletion(String key) {
        Mono<List<String>> mono = repository.suggestBySingleField("suggestion", key);
        return mono;
    }

    /**
     * 搜索产品
     * @param search
     * @return
     */
    @Override
    public Mono<PageInfo<Goods>> searchGoodsByCondition(Search search) {
        //判断key是否为空
        if(StringUtils.isEmpty(search.getKey())){
            throw new LyException("请输入搜索条件",400);
        }
        //构建条件搜索器
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //设置参数
        //根据key搜索
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.matchQuery("title", search.getKey()));
        //判断其他条件
        if(!CollectionUtils.isEmpty(search.getFilters())){
            Map<String, Object> filters = search.getFilters();
            filters.forEach((key,value)->{
                queryBuilder.must(QueryBuilders.matchQuery(key,value));
            });
        }
        //分页，以及每页数量
        searchSourceBuilder.query(queryBuilder).from(search.getPage()).size(30);
        //排序
        if(StringUtils.isNoneBlank(search.getSortBy())){
            searchSourceBuilder.sort(search.getSortBy(),search.getDesc()? SortOrder.DESC:SortOrder.ASC);

        }
        //高亮
        searchSourceBuilder.highlighter(
                new HighlightBuilder().field("title").preTags("<am>").postTags("</am>"));
        Mono<PageInfo<Goods>> mono = repository.queryBySourceBuilderForPageHighlight(searchSourceBuilder);
        return mono;
    }

    /**
     * 加载数据
     */
    private void loadData() {
        int a =1;
        //循环存储，直到最后一页
        while (true) {
            log.info("开始导入第{}页数据",a);
            //分页查询数据
            QueryPageDto queryPageDto = new QueryPageDto();
            queryPageDto.setSaleable(true);
            queryPageDto.setRows(100);
            queryPageDto.setPage(a);

            //查询数据
            PageDTO<SpuDto> pageDTO = feignController.queryGoodsByPage(queryPageDto);
            List<SpuDto> items = pageDTO.getItems();
            List<Goods> list = items.stream().map(this::conserve).collect(Collectors.toList());
            //批量存储
            repository.saveAll(list);
            log.info("导入第{}页数据结束",a);
            //翻页
            a++;
            if(a>pageDTO.getTotalPage()){
                break;
            }
        }
    }

    /**
     * 创建索引库
     */
    private void createIndex() {
        //先判断索引库是否存在
        try {
           repository.deleteIndex();
           log.info("数据库已删除");
        } catch (Exception e) {
            log.info("数据库不存在",e);
        }
        //创建新的索引库
        repository.createIndex("{\n" +
                "  \"settings\": {\n" +
                "    \"analysis\": {\n" +
                "      \"analyzer\": {\n" +
                "        \"my_pinyin\": {\n" +
                "          \"tokenizer\": \"ik_smart\",\n" +
                "          \"filter\": [\n" +
                "            \"py\"\n" +
                "          ]\n" +
                "        }\n" +
                "      },\n" +
                "      \"filter\": {\n" +
                "        \"py\": {\n" +
                "\t\t  \"type\": \"pinyin\",\n" +
                "          \"keep_full_pinyin\": true,\n" +
                "          \"keep_joined_full_pinyin\": true,\n" +
                "          \"keep_original\": true,\n" +
                "          \"limit_first_letter_length\": 16,\n" +
                "          \"remove_duplicated_term\": true\n" +
                "        }\n" +
                "      }\n" +
                "    }\n" +
                "  },\n" +
                "  \"mappings\": {\n" +
                "    \"properties\": {\n" +
                "      \"id\": {\n" +
                "        \"type\": \"keyword\"\n" +
                "      },\n" +
                "      \"suggestion\": {\n" +
                "        \"type\": \"completion\",\n" +
                "        \"analyzer\": \"my_pinyin\",\n" +
                "        \"search_analyzer\": \"ik_smart\"\n" +
                "      },\n" +
                "      \"title\":{\n" +
                "        \"type\": \"text\",\n" +
                "        \"analyzer\": \"my_pinyin\",\n" +
                "        \"search_analyzer\": \"ik_smart\"\n" +
                "      },\n" +
                "      \"image\":{\n" +
                "        \"type\": \"keyword\",\n" +
                "        \"index\": false\n" +
                "      },\n" +
                "      \"updateTime\":{\n" +
                "        \"type\": \"date\"\n" +
                "      },\n" +
                "      \"specs\":{\n" +
                "        \"type\": \"nested\",\n" +
                "        \"properties\": {\n" +
                "          \"name\":{\"type\": \"keyword\" },\n" +
                "          \"value\":{\"type\": \"keyword\" }\n" +
                "        }\n" +
                "      }\n" +
                "    }\n" +
                "  }\n" +
                "}");
    }

    //转换成goods
    public Goods conserve(SpuDto spuDto){
        //创建拼音不全搜素字段，类型为set集合,有品牌名字，种类名字，商品名称
        HashSet<String> set = new HashSet<>();
        String brandName = spuDto.getBrandName();
        //查询的分类名字格式为：一级种类/二级种类/三级种类，所以要切割成数组，分别添加
        String[] strings = spuDto.getCategoryName().split("/");
        String name = spuDto.getName();
        set.add(brandName);
        set.add(name);
        //添加分类名字
        Collections.addAll(set,strings);
        //补全spec，类型为list(map(string,object));
        List<SpecParamDto> paramDtos = feignController.queryParamValue(spuDto.getId(), true);
        ArrayList<Map<String, Object>> list = new ArrayList<>();
        for (SpecParamDto paramDto : paramDtos) {
            HashMap<String, Object> hashMap = new HashMap<>(2);
            hashMap.put("name",paramDto.getName());
            Object o = chooseSegment(paramDto);
            hashMap.put("value",o);
            list.add(hashMap);
        }
        //补全销量
        List<SkuDto> spuDtoSkus = spuDto.getSkus();
        //如果为空，则自己去查
        if(CollectionUtils.isEmpty(spuDtoSkus)){
            spuDtoSkus = feignController.querySkuBySpuId(spuDto.getId());
        }
//        Long sold=0L;
//        for (SkuDto skus : spuDtoSkus) {
//            sold+= skus.getSold();
//        }
        long sold = spuDtoSkus.stream().mapToLong(SkuDto::getSold).sum();
        //价格
//        HashSet<Long> longs = new HashSet<>();
        Set<Long> priceSet = spuDtoSkus.stream().map(SkuDto::getPrice).collect(Collectors.toSet());
        //图片
        String images = spuDtoSkus.get(0).getImages();
        //如果是多个，则切割，不是多个，则不切割
        String s = StringUtils.substringBefore(images, ",");
        //补全goods
        Goods goods = new Goods();
        goods.setUpdateTime(new Date());
        goods.setTitle(spuDto.getTitle());
        goods.setSuggestion(set);
        goods.setSpecs(list);
        goods.setSold(sold);
        goods.setPrices(priceSet);
        goods.setImage(s);
        goods.setId(spuDto.getId());
        goods.setCategoryId(spuDto.getCid3());
        goods.setBrandId(spuDto.getBrandId());


        return goods;
    };

    //传入的参数为ParamDto
    //判断paramDto的segments值是否存在，存在则进行比较，不存在则不替换
//    public void  optimizeValue(List<SpecParamDto> paramDtos,HashMap<String, Object> hashMap, ArrayList<Map<String, Object>> list){
//        for (SpecParamDto paramDto : paramDtos) {
//            String segments = paramDto.getSegments();
//            Object value = paramDto.getValue();
//            //如果不存在
//            if(StringUtils.isEmpty(segments)){
//               hashMap.put("name",paramDto.getName());
//               hashMap.put("value",paramDto.getValue());
//               list.add(hashMap);
//            }
//            //如果存在
//            //各个范围的数组
//            String[] strings = segments.split(",");
//            //遍历，比较
//            String s = paramDto.getValue().toString();
//            int i = Integer.parseInt(s);
//            int i1 = Integer.parseInt(strings[0]);
//            int i2 = Integer.parseInt(strings[1]);
//            if(i>=i1&&i<=i2){
//
//            }
//        }
//
//        }


    //对参数值为复数的值进行优化
    private Object chooseSegment(SpecParamDto p) {
        Object value = p.getValue();
        if (value == null || StringUtils.isBlank(value.toString())) {
            return "其它";
        }
        if(!p.getNumeric() || StringUtils.isBlank(p.getSegments()) || value instanceof Collection){
            return value;
        }
        double val = parseDouble(value.toString());
        String result = "其它";
        // 保存数值段
        for (String segment : p.getSegments().split(",")) {
            String[] segs = segment.split("-");
            // 获取数值范围
            double begin = parseDouble(segs[0]);
            double end = Double.MAX_VALUE;
            if (segs.length == 2) {
                end = parseDouble(segs[1]);
            }
            // 判断是否在范围内
            if (val >= begin && val < end) {
                if (segs.length == 1) {
                    result = segs[0] + p.getUnit() + "以上";
                } else if (begin == 0) {
                    result = segs[1] + p.getUnit() + "以下";
                } else {
                    result = segment + p.getUnit();
                }
                break;
            }
        }
        return result;
    }

    //将字符串装换成double类型
    private double parseDouble(String str) {
        try {
            return Double.parseDouble(str);
        } catch (Exception e) {
            return 0;
        }
    }
    }
